﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using MailKit.Net.Proxy;
using System.Net.Http;
using System.Threading.Tasks;
using Org.BouncyCastle.Ocsp;
using System.Net.Http.Headers;
using Org.BouncyCastle.Bcpg.OpenPgp;
using Microsoft.Extensions.Configuration;
using System.Security;
using Maltose.Configuration;
using Maltose.Log;

namespace Maltose.MicroService
{
    /// <summary>
    /// 请求服务
    /// </summary>
    public class UseMicroServiceClient
    {
        /// <summary>
        /// 客户端
        /// </summary>
        public HttpClient Client { get; }


        /// <summary>
        /// 签名需要的 apiKey
        /// </summary>
        public string ApiKey { get; set; } = string.Empty;

        /// <summary>
        /// 签名需要的 密钥
        /// </summary>
        public string ApiPassword { get; set; } = string.Empty;

        /// <summary>
        /// 默认基础请求头，通常可能是固定的值
        /// </summary>
        public Dictionary<string, string> DefaultBaseHeaders { get; set; } = new Dictionary<string, string>();

        /// <summary>
        /// 请求内容类型 默认 application/json
        /// </summary>
        public string ContentType { get; set; } = "application/json";

        /// <summary>
        /// 设置超时时间 默认为30秒
        /// </summary>
        public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(30);

        /// <summary>
        /// 转码格式
        /// </summary>
        public Encoding Encode { get; set; } = Encoding.UTF8;


        /// <summary>
        /// 打开请求日志记录
        /// </summary>
        public bool OpenRequestBeforeLog { get; set; } = true;


        /// <summary>
        /// 网关相关参数
        /// </summary>
        public MicroServiceUriConfig Host { get; private set; } = new MicroServiceUriConfig();


        /// <summary>
        /// 请求服务
        /// </summary>
        /// <param name="client">客户端</param>
        public UseMicroServiceClient(HttpClient client)
        {
            Client = client;
        }

        /// <summary>
        /// 请求服务
        /// </summary>
        /// <param name="client">客户端</param>
        /// <param name="searchKey">查找搜索key</param>
        public UseMicroServiceClient(HttpClient client, string searchKey)
        {
            Client = client;
            SetCofing(searchKey);
        }

        /// <summary>
        /// 设置配置文件内容 它位于 appsettings.json MicroService键下
        /// </summary>
        /// <param name="searchKey"></param>
        public void SetCofing(string searchKey)
        {
            var key = $"MicroService:{searchKey}";
            var g = UseConfigFactory.Json.Get<MicroServiceUriConfig>(key);
            if (g == null)
            {
                throw new ArgumentNullException($"微服务客户端找不到 appsettings.json 节点下 {key} 值");
            }
            Host = g;
        }


        /// <summary>
        /// 请求
        /// </summary>
        /// <param name="request"></param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, Dictionary<string, string> headers)
        {

            //请求来源
            request.Headers.TryAddWithoutValidation("Maltose-Request-Source", Host.RequestSource);

            //全局请求头
            if (DefaultBaseHeaders.Count > 0)
            {
                foreach (var item in DefaultBaseHeaders)
                {
                    request.Headers.TryAddWithoutValidation(item.Key, item.Value);
                }
            }

            //添加请求头 可能在请求的时候添加
            if (headers != null && headers.Count >= 0)
            {
                foreach (var item in headers)
                {
                    request.Headers.TryAddWithoutValidation(item.Key, item.Value);
                }
            }


            if (OpenRequestBeforeLog)
            {
                string content = string.Empty;
                if (request.Method == HttpMethod.Post)
                {
                    content = await request.Content.ReadAsStringAsync();
                }
                var msg = $"[{request.Method}] {request.RequestUri.AbsoluteUri} 参数: {content} ";
                UseLog.Info(msg, "微服务请求前");
            }


            return await Client.SendAsync(request);
        }

        #region POST请求

        /// <summary>
        /// POST请求
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="param"></param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<string> PostAsync(string uri, string param = "", Dictionary<string, string> headers = null)
        {
            if (string.IsNullOrWhiteSpace(param)) { param = ""; }

            if (!string.IsNullOrEmpty(Host.Url))
            {
                uri = $"{Host.Url}{uri}";
            }

            var content = new StringContent(param, Encode);
            content.Headers.ContentType = new MediaTypeHeaderValue(ContentType);

            var request = new HttpRequestMessage(HttpMethod.Post, uri);
            request.Content = content;

            var response = await SendAsync(request, headers);

            if (response.StatusCode != HttpStatusCode.OK)
            {
                var raw = await response.Content.ReadAsStringAsync();
                UseLog.Debug($" 接口:{uri}  状态码 [{response.StatusCode}] {raw}", "微服务请求结果");
                throw new MicroServiceException("请求接口返回不是 200 结果");
            }

            return await response.Content.ReadAsStringAsync();
        }

        /// <summary>
        /// POST请求
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="uri">地址</param>
        /// <param name="param">参数</param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<T> PostAsync<T>(string uri, string param = "", Dictionary<string, string> headers = null)
        {
            var rs = await PostAsync(uri, param, headers);
            return rs.JsonToObject<T>();
        }

        /// <summary>
        /// POST请求 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="uri">地址</param>
        /// <param name="param">参数</param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<MicroServiceDataResult<T>> PostResultAsync<T>(string uri, string param = "", Dictionary<string, string> headers = null)
        {
            return await PostAsync<MicroServiceDataResult<T>>(uri, param, headers);
        }

        /// <summary>
        /// POST请求 把参数转换成JSON字符串
        /// </summary>
        /// <param name="uri">地址</param>
        /// <param name="param">可转换为JSON支持的对象</param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<string> PostJsonAsync(string uri, object param = null, Dictionary<string, string> headers = null)
        {
            if (param == null)
            {
                param = new object();
            }
            return await PostAsync(uri, param.ToJson(), headers);
        }

        /// <summary>
        /// POST请求 把参数转换成JSON字符串
        /// </summary>
        /// <param name="uri">地址</param>
        /// <param name="param">可转换为JSON支持的对象</param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<T> PostJsonAsync<T>(string uri, object param = null, Dictionary<string, string> headers = null)
        {
            var rs = await PostJsonAsync(uri, param, headers);
            return rs.JsonToObject<T>();
        }


        /// <summary>
        /// POST请求 把参数转换成JSON字符串
        /// </summary>
        /// <param name="uri">地址</param>
        /// <param name="param">可转换为JSON支持的对象</param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<MicroServiceDataResult<T>> PostJsonResultAsync<T>(string uri, object param = null, Dictionary<string, string> headers = null)
        {
            return await PostJsonAsync<MicroServiceDataResult<T>>(uri, param, headers);
        }

        /// <summary>
        /// POST请求 内容为 application/x-www-form-urlencoded
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="data"></param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<string> PostAsync(string uri, FormUrlEncodedData data, Dictionary<string, string> headers = null)
        {

            if (!string.IsNullOrEmpty(Host.Url))
            {
                uri = $"{Host.Url}{uri}";
            }

            var content = new StringContent(data.ToString(), Encode);
            content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");

            var request = new HttpRequestMessage(HttpMethod.Post, uri);
            request.Content = content;

            var response = await SendAsync(request, headers);
            return await response.Content.ReadAsStringAsync();
        }


        /// <summary>
        /// POST请求 内容为 application/x-www-form-urlencoded
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="data"></param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<T> PostAsync<T>(string uri, FormUrlEncodedData data, Dictionary<string, string> headers = null)
        {
            var rs = await PostAsync(uri, data, headers);
            return rs.JsonToObject<T>();
        }

        /// <summary>
        /// POST请求 内容为 application/x-www-form-urlencoded
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="uri">地址</param>
        /// <param name="data">参数</param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<MicroServiceDataResult<T>> PostResultAsync<T>(string uri, FormUrlEncodedData data, Dictionary<string, string> headers = null)
        {
            return await PostAsync<MicroServiceDataResult<T>>(uri, data, headers);
        }

        /// <summary>
        /// 带有签名的post请求 如果不设置 key password 则优先获取属性值
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="data"></param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<string> PostAsync(string uri, FormUrlSignEncodedData data, Dictionary<string, string> headers = null)
        {
            if (string.IsNullOrWhiteSpace(data.ApiKey))
            {
                data.ApiKey = ApiKey;
            }

            if (string.IsNullOrWhiteSpace(data.Password))
            {
                data.Password = ApiPassword;
            }



            if (!string.IsNullOrEmpty(Host.Url))
            {
                uri = $"{Host.Url}{uri}";
            }

            var content = new StringContent(data.ToString(), Encode);
            content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");

            var request = new HttpRequestMessage(HttpMethod.Post, uri);
            request.Content = content;

            var response = await SendAsync(request, headers);
            return await response.Content.ReadAsStringAsync();
        }


   

        /// <summary>
        /// POST请求 内容为 application/x-www-form-urlencoded
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="data"></param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<T> PostAsync<T>(string uri, FormUrlSignEncodedData data, Dictionary<string, string> headers = null)
        {
            var rs = await PostAsync(uri, data, headers);
            return rs.JsonToObject<T>();
        }

        /// <summary>
        /// POST请求 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="uri">地址</param>
        /// <param name="data">参数</param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<MicroServiceDataResult<T>> PostResultAsync<T>(string uri, FormUrlSignEncodedData data, Dictionary<string, string> headers = null)
        {
            var rs = await PostAsync(uri, data, headers);
            return rs.JsonToObject<MicroServiceDataResult<T>>();
        }

        #endregion


        #region GET

        /// <summary>
        /// Get请求
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<string> GetAsync(string uri, Dictionary<string, string> headers = null)
        {
            if (!string.IsNullOrEmpty(Host.Url))
            {
                uri = $"{Host.Url}{uri}";
            }
            var request = new HttpRequestMessage(HttpMethod.Get, uri);
            var response = await SendAsync(request, headers);

            if (response.StatusCode != HttpStatusCode.OK)
            {
                var raw = await response.Content.ReadAsStringAsync();
                UseLog.Debug($" 接口:{uri}  状态码 [{response.StatusCode}] {raw}", "微服务请求结果");
                throw new MicroServiceException("请求接口返回不是 200 结果");
            }
            return await response.Content.ReadAsStringAsync();
        }

        /// <summary>
        /// Get请求
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="uri"></param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<T> GetAsync<T>(string uri, Dictionary<string, string> headers = null)
        {
            var rs = await GetAsync(uri, headers);
            return rs.JsonToObject<T>();
        }

        /// <summary>
        /// Get请求
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<MicroServiceDataResult<T>> GetResultAsync<T>(string uri, Dictionary<string, string> headers = null)
        {
            var rs = await GetAsync(uri, headers);
            var json = rs.JsonToObject<MicroServiceDataResult<T>>();
            return json;
        }

        #endregion

    }
}
